package com.xneure.enging.widget;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.xneure.code.log.ILog;
import com.xneure.code.log.LogManage;
import com.xneure.enging.Context;
import com.xneure.enging.ui.UiElement;
import com.xneure.enging.ui.event.UiEvent;
import com.xneure.enging.widget.event.Event;
import com.xneure.enging.widget.event.EventType;
import com.xneure.utils.ObjectUtil;
import com.xneure.utils.bean.GUID;
import com.xneure.utils.intf.GenericsFilter;

public class Widget<H extends UiElement> implements Control {

	private transient Context context;
	protected Map<GUID, Control> elemMap;
	protected Map<Event, EventType> eventMap = new LinkedHashMap<Event, EventType>(20);
	private H htmlEle;
	private Control parent;
	private boolean valid = true;
	private ILog log = LogManage.newLog();

	public Widget(Control parent) {
		this.parent = parent;
		initHtml();
		if (parent != null) {
			context = parent.getContext();
			parent.addElement(this);
			WidgetManage.register(this);
		}
	}

	@SuppressWarnings("unchecked")
	protected void initHtml() {
		try {
			Class<?> controlsClass = getControlsClass();
			try {
				htmlEle = (H) controlsClass.getConstructor(getEleType()).newInstance(parent.getHtmlEle());
			} catch (Exception e) {
				htmlEle = (H) controlsClass.newInstance();
			}
		} catch (Exception e) {
			log.debug(e.getMessage());
		}
	}

	protected Class<?> getEleType() {
		return UiElement.class;
	}

	@Override
	public Control getParent() {
		return parent;
	}

	@Override
	public GUID getId() {
		return htmlEle.getId();
	}

	public void setId(GUID id) {
		htmlEle.setId(id);
	}

	@Override
	public H getHtmlEle() {
		return htmlEle;
	}

	public void addElement(Control elem) {
		if (null == elemMap) {
			elemMap = new LinkedHashMap<GUID, Control>(20);
		}
		elemMap.put(elem.getId(), elem);
		htmlEle.addElement(elem.getHtmlEle());
	}

	@Override
	public Context getContext() {
		return context;
	}

	protected void setContext(Context context) {
		this.context = context;
	}

	@Override
	public Map<GUID, Control> getElemMap() {
		return elemMap;
	}

	@Override
	public List<Control> getElems() {
		return new ArrayList<Control>(elemMap.values());
	}

	public void setElemMap(Map<GUID, Control> elemMap) {
		this.elemMap = elemMap;
	}

	@Override
	public Map<Event, EventType> getEventMap() {
		return eventMap;
	}

	public void addEvent(Event event) {
		addEvent(event, event.getEveType());
	}

	public void addEvent(Event event, EventType type) {
		this.eventMap.put(event, type);
		htmlEle.addEvent(new UiEvent(type.name()));
	}

	public void setStyle(String name, String value) {
		htmlEle.setStyle(name, value);
	}

	public Object getStyle(String name) {
		return htmlEle.getStyle(name);
	}

	protected Class<?> getControlsClass() {
		return ObjectUtil.getGenerics(new GenericsFilter() {

			@Override
			public Class<?> targetClass() {
				return UiElement.class;
			}

			@Override
			public Class<?> superClass() {
				return Widget.class;
			}

			@Override
			public Class<?> searchClass() {
				return meClass();
			}
		});
	}

	private Class<?> meClass() {
		return this.getClass();
	}

	@Override
	public void event(Object src, EventType type) {
		if (null != eventMap) {
			for (Entry<Event, EventType> eve : eventMap.entrySet()) {
				if (eve.getValue() == type) {
					eve.getKey().event(onEvent(src));
				}
			}
		}
	}

	protected Widget<H> onEvent(Object src) {
		return this;
	}

	public void remove(Control w) {
		if (elemMap.containsKey(w.getId())) {
			WidgetManage.remove(this);
			elemMap.remove(w.getId());
			htmlEle.remove(w.getHtmlEle());
			event(this, EventType.DEL);
		}
	}

	public boolean isValid() {
		return valid;
	}

	public void setProperty(String name, Object value) {
		htmlEle.setProperty(name, value);
	}

	public Object getProperty(String name) {
		return htmlEle.getProperty(name);
	}

	@Override
	public void remove() {
		parent.remove(this);
	}
}
